package com.ray.tool;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 反射 - 工具类
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2023/8/30 20:28
 **/
public class ReflectTools {

    /**
     * 工具类中的方法都是静态方法访问的，因此将构造器私有不允许创建对象
     *
     * @author LiaoYuXing-Ray 2023/9/7 10:28
     */
    private ReflectTools() {
        throw new AssertionError();
    }

    public static Field[] getClsFields(Class<?> cls) {
        return getClsFields(cls, false);
    }

    /**
     * 获取一个类及其父类的所有字段（包括私有、保护、默认和公共字段），并将它们存储在一个数组中。
     * 如果isIncludeParent参数为true，则还会包含父类的字段；否则，只包含当前类的字段
     *
     * @param cls 类
     * @param isIncludeParent 参数为true，则还会包含父类的字段；否则，只包含当前类的字段
     * @return java.lang.reflect.Field[]
     * @author LiaoYuXing-Ray 2023/9/18 16:34
     **/
    public static Field[] getClsFields(Class<?> cls, boolean isIncludeParent) {
        if (cls == null || cls == Object.class) {
            return null;
        }

        Map<String, Field> fieldMap = new HashMap<>();

        for (Field field : cls.getDeclaredFields()) {
            fieldMap.put(field.getName(), field);
        }

        if (!isIncludeParent) {
            return fieldMap.values().toArray(new Field[0]);
        }

        Class<?> sekCls = cls;
        while (sekCls != null && sekCls != Object.class) {
            for (Field field : sekCls.getDeclaredFields()) {
                if (!fieldMap.containsKey(field.getName())) {
                    fieldMap.put(field.getName(), field);
                }
            }
            sekCls = sekCls.getSuperclass();
        }

        return fieldMap.values().toArray(new Field[0]);
    }

    public static Method[] getClsMethods(Class<?> cls) {
        return getClsMethods(cls, false);
    }

    /**
     * 获取一个类及其父类的所有方法（包括私有、保护、默认和公共方法），并将它们存储在一个数组中。
     * 如果isIncludeParent参数为true，则还会包含父类的方法；否则，只包含当前类的方法
     *
     * @param cls 类
     * @param isIncludeParent 参数为true，则还会包含父类的方法；否则，只包含当前类的方法
     * @return java.lang.reflect.Field[]
     * @author LiaoYuXing-Ray 2023/9/18 16:34
     **/
    public static Method[] getClsMethods(Class<?> cls, boolean isIncludeParent) {
        if (cls == null || cls == Object.class) {
            return null;
        }

        Map<String, Method> methodMap = new HashMap<>();

        for (Method method : cls.getDeclaredMethods()) {
            methodMap.put(method.getName(), method);
        }

        if (!isIncludeParent) {
            return methodMap.values().toArray(new Method[0]);
        }

        Class<?> sekCls = cls;
        while (sekCls != null && sekCls != Object.class) {
            for (Method method : sekCls.getDeclaredMethods()) {
                if (!methodMap.containsKey(method.getName())) {
                    methodMap.put(method.getName(), method);
                }
            }
            sekCls = sekCls.getSuperclass();
        }

        return methodMap.values().toArray(new Method[0]);
    }

}

